package com.bestcem.xm.survey.service.impl;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.component.mybatis.service.impl.XmServiceImpl;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.survey.entity.SurveyRespondentAttachment;
import com.bestcem.xm.survey.entity.UploadFileInfo;
import com.bestcem.xm.survey.entity.UploadFileMap;
import com.bestcem.xm.survey.mapper.SurveyRespondentAttachmentMapper;
import com.bestcem.xm.survey.mapper.UploadFileInfoMapper;
import com.bestcem.xm.survey.mapper.UploadFileMapMapper;
import com.bestcem.xm.survey.service.SurveyRespondentAttachmentService;
import com.bestcem.xm.survey.util.CommonUtil;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static com.bestcem.xm.common.core.constant.Constants.SEPARATOR;
import static com.bestcem.xm.common.core.enums.ReqErrorCodeEnum.NOT_FOUND;
import static com.bestcem.xm.survey.enums.FileInfoFTypeEnum.FILEINFO_FTYPE_NONE;
import static com.bestcem.xm.survey.enums.FileInfoPolicyEnum.FILEINFO_POLICY_OSS;
import static com.bestcem.xm.survey.grpc.v1.services.RespondentAttachmentFtype.*;
import static com.bestcem.xm.survey.util.SurveyConstant.ATTACHMENT_FILE_NAME;
import static com.bestcem.xm.survey.util.SurveyConstant.FTYPE_SUB_DIR_DICT;

/**
 * @author guita
 * @description 针对表【ds_survey_respondentattachment】的数据库操作Service实现
 * @createDate 2023-01-09 15:15:37
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SurveyRespondentAttachmentServiceImpl extends XmServiceImpl<SurveyRespondentAttachmentMapper, SurveyRespondentAttachment>
        implements SurveyRespondentAttachmentService {

    private static final String ROOT_FILE_PATH = System.getProperty("user.dir");
    private static final String TEMP_PATH = ROOT_FILE_PATH + File.separator + "temp" + File.separator;

    private @NonNull UploadFileMapMapper uploadFileMapMapper;
    private @NonNull UploadFileInfoMapper uploadFileInfoMapper;
    //private @NonNull OssService ossService;
    private @NonNull StorageService storageService;

    @Override
    public List<SurveyRespondentAttachment> attachment(String projectId, Integer seq, List<MultipartFile> files, Integer qid, Integer optionId, Boolean keepExt) {
        List<SurveyRespondentAttachment> new_atts = new ArrayList<>();
        for (MultipartFile file : files) {
            Assert.notNull(file.getContentType(), "error:文件类型不能数为空");
            String file_type = file.getContentType().split("/")[0];
            int ftype;
            if ("image".equals(file_type)) {
                ftype = RESPONDENTATTACHMENT_FTYPE_IMAGE.getNumber();
            } else if ("video".equals(file_type)) {
                ftype = RESPONDENTATTACHMENT_FTYPE_VIDEO.getNumber();
            } else if ("audio".equals(file_type)) {
                ftype = RESPONDENTATTACHMENT_FTYPE_AUDIO.getNumber();
            } else {
                ftype = RESPONDENTATTACHMENT_FTYPE_UNKNOWN.getNumber();
            }
            new_atts.add(saveAttachment(projectId, seq, qid, file, optionId, ftype, keepExt));
        }
        return new_atts;
    }

    /**
     * @param projectId 问卷id
     * @param seq       答卷seq
     * @param qid       请求参数，问题gid
     * @param file      文件
     * @param optionId  请求参数，选项id
     * @param ftype
     * @param keepExt   是否保留文件后缀
     */
    private SurveyRespondentAttachment saveAttachment(String projectId, Integer seq, Integer qid, MultipartFile file, Integer optionId, Integer ftype, Boolean keepExt) {
        long fileSize = file.getSize();
        String filename = file.getOriginalFilename();
        JSONObject fileMapObj = createFilemap(file, projectId, ftype, null, keepExt);
        String download_url = fileMapObj.getString("file_path");
        String file_map_id = fileMapObj.getString("file_map_id");
        SurveyRespondentAttachment attachment = new SurveyRespondentAttachment();
        attachment.setProjectId(projectId);
        attachment.setSeq(seq);
        attachment.setQid(qid);
        attachment.setOptionId(optionId);
        attachment.setSize((int) fileSize);
        attachment.setFilemapId(file_map_id);
        attachment.setUrl(download_url);
        attachment.setName(filename);
        attachment.setFtype(Optional.ofNullable(ftype).orElse(RESPONDENTATTACHMENT_FTYPE_UNKNOWN.getNumber()));
        baseMapper.insert(attachment);
        return attachment;
    }

    /**
     * 创建文件
     *
     * @param file      文件
     * @param projectId 文件所在项目，删除项目时根据该字段删除文件
     * @param ftype
     * @param keepExt
     * @return FileMap文档ID, 前端访问路径
     */
    private JSONObject createFilemap(MultipartFile file, String projectId, Integer ftype, Boolean duplicate, Boolean keepExt) {
        String file_name = file.getOriginalFilename();
        JSONObject fileMapObj;
        if (StrUtil.isNotEmpty(file_name) && !ATTACHMENT_FILE_NAME.contains(file_name)) {
            CommonUtil.checkExt(file_name, null);
        }
        Assert.notNull(file_name, "error:文件名不能数为空");
        //形如'.png'
        String ext = keepExt ? file_name.substring(file_name.lastIndexOf(".")) : null;
        fileMapObj = createFileinfo(file, file_name, ftype, duplicate, ext);
        UploadFileMap uploadFileMap = new UploadFileMap();
        uploadFileMap.setSysId("survey");
        uploadFileMap.setFileName(file_name);

        UploadFileInfo fileInfo = (UploadFileInfo) fileMapObj.remove("fileInfo");
        if (Objects.nonNull(fileInfo)) {
            uploadFileMap.setFileInfoId(fileInfo.getId());
            uploadFileMap.setOriginFileInfoId(fileInfo.getId());
        }
        uploadFileMapMapper.insert(uploadFileMap);
        fileMapObj.put("file_map_id", uploadFileMap.getId());
        return fileMapObj;
    }

    /**
     * 创建FileInfo，并保存文件到系统
     *
     * @param file      文件
     * @param file_name
     * @param ftype     文件类型, 这个文件类型仅仅用于目录分类
     * @param duplicate 是否复制
     * @param ext       文件后缀，包含'.', 形如：'.png'
     * @return FileInfo 文档对象
     */
    private JSONObject createFileinfo(MultipartFile file, String file_name, Integer ftype, Boolean duplicate, String ext) {
        String file_id;
        try {
            file_id = DigestUtil.md5Hex(file.getInputStream()) + Optional.ofNullable(ext).orElse("");
        } catch (IOException e) {
            throw new BusinessException("文件读取异常：{}", e);
        }
        JSONObject res = new JSONObject();
        if (Objects.equals(true, duplicate)) {
            LambdaQueryWrapper<UploadFileInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UploadFileInfo::getFileId, file_id).last("limit 1");
            UploadFileInfo fileInfo = uploadFileInfoMapper.selectOne(queryWrapper);
            if (Objects.nonNull(fileInfo)) {
                res.put("fileInfo", fileInfo);
                res.put("file_path", fileInfo.getUrl());
                return res;
            }
        }
        long file_size = file.getSize();
        String file_path = null;
        String ossPath = OssPathEnum.SURVEY.getPath() + genFilePath(file_id, ftype) + SEPARATOR;
        File parentfile = new File(TEMP_PATH);
        if (!parentfile.exists()) {
            parentfile.mkdirs();
        }
        File tempFile = new File(TEMP_PATH, file_name);
        log.info("输出：{}", tempFile);
        try {
            file.transferTo(tempFile);
            //file_path = ossService.uploadSimpleFile2(tempFile, file_id.substring(5), ossPath, 0, null, "答题-附件上传", OssPathEnum.TEMP_SURVEY);
            file_path = storageService.upload(tempFile, file_id.substring(5), ossPath, new Dict()).getUrl();
        } catch (Exception e) {
            log.error("文件上传失败：", e);
        }
        tempFile.delete();
        LambdaQueryWrapper<UploadFileInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UploadFileInfo::getFileId, file_id).last("limit 1");
        UploadFileInfo fileInfo = uploadFileInfoMapper.selectOne(queryWrapper);
        if (Objects.isNull(fileInfo)) {
            fileInfo = new UploadFileInfo();
            fileInfo.setFileId(file_id);
            fileInfo.setFileSize((int) file_size);
            fileInfo.setFtype(ftype);
            //默认值
            fileInfo.setPolicy(FILEINFO_POLICY_OSS.getValue());
            fileInfo.setUrl(file_path);
            uploadFileInfoMapper.insert(fileInfo);
        } /*else {
            fileInfo.setFileSize((int) file_size);
            fileInfo.setFtype(ftype);
            fileInfo.setUrl(file_path);
            uploadFileInfoMapper.updateById(fileInfo);
        }*/
        res.put("fileInfo", fileInfo);
        res.put("file_path", file_path);
        return res;
    }

    /**
     * 生成文件路径
     *
     * @param file_id 文件内容的hash
     * @param ftype
     * @return 相对路径，分为三级 xx/xxx/xxxx
     */
    private String genFilePath(String file_id, Integer ftype) {
        String fpath = file_id.substring(0, 2) + SEPARATOR + file_id.substring(2, 5);
        if (FILEINFO_FTYPE_NONE.getValue() != ftype) {
            String sub_dir = FTYPE_SUB_DIR_DICT.get(ftype);
            fpath = sub_dir + SEPARATOR + fpath;
        }
        return fpath;
    }

    @Override
    public int deleteAttachment(String projectId, Integer seq, String attId) {
        LambdaQueryWrapper<SurveyRespondentAttachment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SurveyRespondentAttachment::getId, attId);
        queryWrapper.eq(SurveyRespondentAttachment::getProjectId, projectId);
        queryWrapper.eq(SurveyRespondentAttachment::getSeq, seq);
        SurveyRespondentAttachment attachment = baseMapper.selectOne(queryWrapper);
        if (Objects.isNull(attachment)) {
            throw new BusinessException(String.valueOf(NOT_FOUND.getCode()), String.format("attachment[id={%s},project_id={%s},seq={%s}] not found", attId, projectId, seq));
        }
        baseMapper.deleteById(attachment.getId());
        return 1;
    }

    @Override
    public Object getAttachments(String projectId, Integer seq, Integer qid, Integer optionId) {
        LambdaQueryWrapper<SurveyRespondentAttachment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SurveyRespondentAttachment::getProjectId, projectId);
        queryWrapper.eq(SurveyRespondentAttachment::getSeq, seq);
        queryWrapper.eq(!ObjectUtils.isEmpty(qid), SurveyRespondentAttachment::getQid, qid);
        queryWrapper.eq(!ObjectUtils.isEmpty(optionId), SurveyRespondentAttachment::getOptionId, optionId);

        return baseMapper.selectList(queryWrapper);
    }
}




